use winapi::um::processthreadsapi::{GetCurrentProcessId, OpenProcess};
use winapi::shared::ntdef::{HANDLE, NULL};
use winapi::shared::minwindef::{FALSE};
use winapi::um::winnt::PROCESS_ALL_ACCESS;
use log::{info};


#[allow(dead_code)]
pub struct MemHelper {
    process_handle: HANDLE
}

#[allow(dead_code)]
impl MemHelper {
    pub fn new() -> Self {
        MemHelper { process_handle: NULL }
    }

    pub fn open_process(&mut self) -> bool {
        if self.process_handle != NULL {
            return true;
        }

        // open current process handle
        let process_id = unsafe { GetCurrentProcessId() };
        self.process_handle = unsafe { OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_id) };
        if self.process_handle == NULL {
            info!("Failed to open process handle.");
            false
        }
        else {
            info!("Opened process handle.");
            true
        }
    }

    // we may never close the process handle
    pub fn close_process(&mut self) {
        // close process handle
        if self.process_handle != NULL {
            unsafe { winapi::um::handleapi::CloseHandle(self.process_handle) };
        }
    }

    pub fn read_memory(&mut self, address: u32, buffer: &mut [u8]) -> bool {
        // read memory from game process
        let mut bytes_read: usize = 0;
        let result = unsafe { winapi::um::memoryapi::ReadProcessMemory(self.process_handle, address as *const _, buffer.as_mut_ptr() as *mut _, buffer.len(), &mut bytes_read) };
        result != FALSE
    }

    pub fn write_memory(&mut self, address: u32, buffer: &[u8]) -> bool {
        // write memory to game process
        let mut bytes_written: usize = 0;
        let result = unsafe { winapi::um::memoryapi::WriteProcessMemory(self.process_handle, address as *mut _, buffer.as_ptr() as *const _, buffer.len(), &mut bytes_written) };
        result != FALSE
    }

    pub fn read_float(&mut self, address: u32) -> f32 {
        // read float from game process
        let mut buffer: [u8; 4] = [0; 4];
        self.read_memory(address, &mut buffer);
        unsafe { std::mem::transmute::<[u8; 4], f32>(buffer) }
    }

    pub fn read_pointer(&mut self, address: u32) -> u32 {
        // read pointer from game process
        let mut buffer: [u8; 4] = [0; 4];
        self.read_memory(address, &mut buffer);
        unsafe { std::mem::transmute::<[u8; 4], u32>(buffer) }
    }

    pub fn read_int(&mut self, address: u32) -> i32 {
        // read int from game process
        let mut buffer: [u8; 4] = [0; 4];
        self.read_memory(address, &mut buffer);
        unsafe { std::mem::transmute::<[u8; 4], i32>(buffer) }
    }

    pub fn write_float(&mut self, address: u32, value: f32) {
        // write float to game process
        let buffer: [u8; 4] = unsafe { std::mem::transmute::<f32, [u8; 4]>(value) };
        self.write_memory(address, &buffer);
    }

    pub fn write_pointer(&mut self, address: u32, value: u32) {
        // write pointer to game process
        let buffer: [u8; 4] = unsafe { std::mem::transmute::<u32, [u8; 4]>(value) };
        self.write_memory(address, &buffer);
    }

    pub fn write_int(&mut self, address: u32, value: i32) {
        // write int to game process
        let buffer: [u8; 4] = unsafe { std::mem::transmute::<i32, [u8; 4]>(value) };
        self.write_memory(address, &buffer);
    }
}

unsafe impl Sync for MemHelper {}
